﻿#include <Sys\RenderUnit\SysRenderDatagram\CUBEMAPTEXTURERD.HPP>
#include <Render\Render_Win32\Render_Win32_OpenGL\RENDER_WIN32_OPENGL.HPP>
#include <Sys\RenderUnit\SysDatagramDisposal_OpenGL\VERTEXREGISTRYDDOPENGL.HPP>
//#include <Sys\RenderUnit\SYSDDCLASSID.HPP>

using namespace CxxlMan;
using namespace Cxxl3D;

// 定義在 Texture.cpp
extern void cxxlFASTCALL TextureMatrix(const CSmart_Ptr<const C3DMatrix4x4> &TextureMatrix_Arg);
extern void cxxlFASTCALL BlendMode(unsigned char Mode);
extern bool cxxlFASTCALL AutoTexCoordIndexMode(char Mode);
extern void cxxlFASTCALL TextureMipmapMode(unsigned char Mode);
extern void TextureAddrMode(unsigned char Mode, unsigned int TextureClampBorderRGBA);


GLuint table[] = {
  GL_TEXTURE_CUBE_MAP_NEGATIVE_Z,
  GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
  GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
  GL_TEXTURE_CUBE_MAP_POSITIVE_X,
  GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
  GL_TEXTURE_CUBE_MAP_NEGATIVE_Y
};


// IDatagramDisposal 寄存在 IDepositStore 的資料
class CDDDeposit:public IDDDeposit
{
  GLuint m_TextureID;


  // 取得實作類別，為了避免轉形太花時間
  virtual void *GetInstance()
  {
    return this;
  }

public:
  // Constructor
  CDDDeposit(GLuint TextureID)
  {
    m_TextureID = TextureID;
  }

  // Destructor
  virtual ~CDDDeposit()
  {
    if(m_TextureID)
      glDeleteTextures(1, &m_TextureID);
  }

  GLuint cxxlFASTCALL GetTextureID() const
  {
    return m_TextureID;
  }

};


class CCubemapTextureRD_OpenGL:public IDatagramDisposal_OpenGL, public ICubemapTextureBridge
{
  Smart_Ptr<IVertexRegistryDDOpenGL> m_IVertexRegistryDDOpenGL_Ptr;

  virtual bool cxxlFASTCALL Exec(const Smart_Ptr<IRenderDatagramDisposalCenterOpengl> &IRenderDatagramDisposalCenter_Arg,
    const Smart_Ptr<IRenderDatagram> &IRenderDatagram_Arg, const CxxlMan::CSmart_Ptr<Matrix4x4> &ViewMatrix_Arg)
  {
    // 第一次被叫用才會取得
    if(m_IVertexRegistryDDOpenGL_Ptr.isNULL())
      m_IVertexRegistryDDOpenGL_Ptr =  Smart_Cast<IVertexRegistryDDOpenGL>(IRenderDatagramDisposalCenter_Arg->GetIDatagramDisposal_OpenGL(IVertexRegistryOpenGL_ClassID));

    Lock(IRenderDatagram_Arg);

    Smart_Ptr<ICubemapTextureRD> ICubemapTextureRD_Ptr = (ICubemapTextureRD*)GetDefaultInterface(IRenderDatagram_Arg);
    Smart_Ptr<DepositStore> DepositStore_Ptr = (ICubemapTextureRD *)ICubemapTextureRD_Ptr;
    Smart_Ptr<IDDDeposit> IDDDeposit_Ptr = GetDeposit(DepositStore_Ptr);

    Smart_Ptr<CDDDeposit> CDDDeposit_Ptr(NULL);
    if(IDDDeposit_Ptr.isNULL())
    {
      const unsigned char ***Mipmaps; 
      const unsigned int **WidthHeight; 
      unsigned int LevelNum;

      
      if(GetMipmap(&Mipmaps,&WidthHeight,&LevelNum,ICubemapTextureRD_Ptr))
      {
        GLuint TextureID;
        glGenTextures( 1, &TextureID );
        glBindTexture( GL_TEXTURE_CUBE_MAP, TextureID );

        for(int i = 0; i < 6; ++i)
        {
          gluBuild2DMipmaps(table[i], 4, WidthHeight[i][0], WidthHeight[i][0], GL_RGBA, GL_UNSIGNED_BYTE, Mipmaps[i][0]);
          glTexParameteri(table[i], GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
          glTexParameteri(table[i], GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        }

        CDDDeposit_Ptr = new CDDDeposit(TextureID);
        SetDeposit((CDDDeposit *)CDDDeposit_Ptr, DepositStore_Ptr);
      }
    }
    else
      CDDDeposit_Ptr = (CDDDeposit *)IDDDeposit_Ptr->GetInstance();

    UnLock(IRenderDatagram_Arg);


    if(CDDDeposit_Ptr.isNULL() == false)
    {
      unsigned char vMipmapMode;   // 貼圖的 Mipmap 模式  0:None(內定) 1:Bilinear 2:Trilinear 3:Anisotropic filter

      // 自動產生貼圖座標
      // 參數以 D3D9 的 D3DTSS_TCI 為功能基準
      // 0:以頂點在 View 座標系中的 x,y 值作為貼圖的 u,v，頂點的 z 值不使用，內定值(CAMERASPACEPOSITION)
      // 1:以頂點在 View 座標系中的 法向量值 作為貼圖的座標值(CAMERASPACENORMAL)
      // 2:以 反射向量值 作為貼圖的座標值，其值在 View 座標系中的頂點位置和法向量來計算(CAMERASPACEREFLECTIONVECTOR)
      // 3:以頂點在 View 座標系中 法向量的 x,y 值轉換到 [0,1] 區間，作為貼圖的座標值(SPHEREMAP)
      // -1:不使用自動產生貼圖座標
      char vAutoTexCoordIndexMode;

      unsigned char vTextureAddrMode; // 設定貼圖座標模式  0:Repeat(內定) 1:Mirror 2:ClampEdge 3:ClampBorder
      unsigned int vTextureClampBorderRGBA;      // m_bTextureAddrMode 指定為 ClampBorder 時，所用的顏色，內定為 0,0,0,0

      unsigned char vBlendMode;
      CSmart_Ptr<const C3DMatrix4x4> vTextureMatrix_cPtr(NULL);   

      GetAttr(vTextureAddrMode,vTextureClampBorderRGBA,vMipmapMode,vAutoTexCoordIndexMode,vBlendMode,vTextureMatrix_cPtr,ICubemapTextureRD_Ptr);

      if(vAutoTexCoordIndexMode != -1)
      {
        if(AutoTexCoordIndexMode(vAutoTexCoordIndexMode) == false)
          goto ERRQUIT;
      }
      else
      {
        Smart_Ptr<IVertexDD> IVertexDD_Ptr = m_IVertexRegistryDDOpenGL_Ptr->Get();
        if(IVertexDD_Ptr->SetCoordIndex() == false)
          goto ERRQUIT;
      }

      TextureAddrMode(vTextureAddrMode, vTextureClampBorderRGBA);
      TextureMipmapMode(vMipmapMode);
      BlendMode(vBlendMode);
      TextureMatrix(vTextureMatrix_cPtr);

      glDisable( GL_TEXTURE_2D );
      glEnable( GL_TEXTURE_CUBE_MAP );
  	  // 使用 TextureID 貼圖物件
      glBindTexture( GL_TEXTURE_2D, CDDDeposit_Ptr->GetTextureID() );

      return true;
    }


ERRQUIT:
    // 不畫出
    glDisable( GL_TEXTURE_2D );
    glDisable( GL_TEXTURE_CUBE_MAP );
    return true; 

  }

public:
  // Constructor
  CCubemapTextureRD_OpenGL()
    :cxxlObject(Spirit_Easy),
    m_IVertexRegistryDDOpenGL_Ptr(NULL,this)
  {
  }

  // Destructor
  ~CCubemapTextureRD_OpenGL()
  {
  }


};

cxxlObject *cxxlFASTCALL New_CCubemapTextureRD_OpenGL()
{
  return new CCubemapTextureRD_OpenGL;
}